package com.xyh.springboot.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.xyh.springboot.shiro.UserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @Author:kyle
 * @Date:2021/1/4 - 10:26
 * @Project:springboot
 * @Package:com.xyh.springboot.config
 * @Version:1.0
 */
@Configuration
public class ShiroConfig {

    //Realm
    @Bean
    public UserRealm getUserRealm(HashedCredentialsMatcher credentialsMatcher){

        UserRealm userRealm = new UserRealm();
        //自定义Realm中定义加密匹配
        userRealm.setCredentialsMatcher(credentialsMatcher);
        return userRealm;
    }

    //安全管理 底层实现类DefaultWebSecurityManager
    @Bean("securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm,DefaultWebSessionManager sessionManager){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);

        //设置会话管理
        securityManager.setSessionManager(sessionManager);

        return securityManager;
    }

    //shiro过滤器
    @Bean
    public ShiroFilterFactoryBean  getFilterFactoryBean(DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //设置登录认证url，没有登录就跳转到登录界面
        shiroFilterFactoryBean.setLoginUrl("/user/toLogin");

        //没有权限的url
        shiroFilterFactoryBean.setUnauthorizedUrl("/user/toNoAuth");

        //设置controller 权限认证url map是过滤链
        Map<String,String> map = new LinkedHashMap<>();

        map.put("/index","anon");//index开放权限
        map.put("/user/login","anon");//login开放权限
        map.put("/user/toIndex","anon");//toIndex开放权限
        map.put("/user/toLogin","anon");//toLogin开放权限
        map.put("/user/toNoAuth","anon");//toNoAuth开放权限
        map.put("/user/toRegister","anon");//toRegister开放权限

       //授权认证 perms过滤器 [user:add] user模块下的add操作
        map.put("/user/add","perms[user:add]");
        map.put("/user/update","perms[user:update]");
        map.put("/user/delete","perms[user:delete]");

        map.put("/user/**","authc");//user/下的资源都需要认证

        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);

        return shiroFilterFactoryBean;
    }

    //关闭url重写
    @Bean
    public DefaultWebSessionManager getDefaultWebSessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        return sessionManager;
    }

    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }

    /**
     * 开启aop注解支持
     * 即在controller中使用 @RequiresPermissions("user:add")
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();

        //设置安全管理器
        attributeSourceAdvisor.setSecurityManager(securityManager);
        return attributeSourceAdvisor;
    }

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }
    //手动加上注解导致异常的处理器
    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        Properties properties = new Properties();

        /*未授权处理页,注意这里直接跳转页面,不需要在经过Controller*/
        properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "noAuth");

        resolver.setExceptionMappings(properties);
        return resolver;
    }

    //配置加密匹配HashedCredentialsMatcher
    @Bean
    public HashedCredentialsMatcher getHashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // 使用md5 算法进行加密
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        // 设置散列次数： 意为加密几次
        hashedCredentialsMatcher.setHashIterations(1024);

        return hashedCredentialsMatcher;
    }
}
